package edu.unc.comp410.colemangeer.model;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;


/**
 * Class for encapsulating a Set of LineItem into a publicly available
 * listing of CatalogItems.
 * 
 * This class provides the public interface for adding items, changing,
 * quantity of items, removing items, etc. that the Customer makes use
 * of while browsing.
 * 
 * It also provides services such as listing order items.
 * 
 * @author ccoleman
 *
 */

public class OrderItems {
	private static Logger log = Logger.getLogger(OrderItems.class);
	
	// the Catalog Items. If one has 3 of a catalog item and then
	// adds two more of the same item,  the unique catalog item

	private Set<LineItem> items = new HashSet<LineItem>();
	
	//private indexes to control addition and alteration
	private Set<CatalogItem> uniqueCatalogItems = new HashSet<CatalogItem>();
	private Map<CatalogItem,Integer> uniqueItemQuantities = new HashMap<CatalogItem, Integer>();
	
	// do we have a CatalogItem in the item set?
	private boolean  catalogItemExists(CatalogItem item){
		return uniqueCatalogItems.contains(item);
	}
	
	// MUCH cleaner design: Map<CatalogItemId,LineItem>
	
	
	/**
	 * public interface for adding, removing, altering items
	 * TODO: needs testing and refactoring
	 */
	
	//add a new LineItem; if newItem.getCatalogItem() already is here, 
	//alter its quantity to reflect the addition
	
	public void addLineItem(LineItem newItem){
		
		if (catalogItemExists(newItem.getCatalogItem())){
			
			// the Catalog item whose quantity we are altering
			
			CatalogItem item = newItem.getCatalogItem();
			
			// get the existing quantity
			Integer oldQuantity = uniqueItemQuantities.get(item);
			
			//compute the new quantity
			Integer newQuantity = oldQuantity + newItem.getQuantity();
			
			//delete the old LineItem from the item set
			items.remove(new LineItem(item, oldQuantity));
			
			//record the new quantity in the index
			uniqueItemQuantities.put(item, newQuantity);
			
			//place a correct LineItem in the item set
			items.add(new LineItem(newItem.getCatalogItem(), newQuantity));
			
		}
		else{
			uniqueCatalogItems.add(newItem.getCatalogItem());
			uniqueItemQuantities.put(newItem.getCatalogItem(),newItem.getQuantity());
			items.add(newItem);
		}
	}
	
	// alter the quantity of an existing item to newQuantity
	// if the item is not here, add it
	public void alterItemQuantity(CatalogItem item, Integer newQuantity){
		
		if (newQuantity.intValue()==0){
			removeLineItem(item);
			return;
		}
		
		LineItem newLineItem  = new LineItem(item, newQuantity);
		
		if (catalogItemExists(item)){
			
			LineItem itemToRemove = new LineItem(item,uniqueItemQuantities.get(item));
			
			//update quantity in the index
			uniqueItemQuantities.put(item, newQuantity);
			
			//delete existing LineItem with this CatalogItem from the item set
			items.remove(itemToRemove);
			
			// put new line item with correct quantity in the item set
			items.add(newLineItem);
			
		}
		else{
			addLineItem(newLineItem);
		}
		
	}
	
	// get rid of a LineItem and any index artifacts relating to itemToRemove
	
	public void removeLineItem(CatalogItem itemToRemove){
		
		if (catalogItemExists(itemToRemove)){
			
			// remove LineItem from item set
			items.remove(new LineItem(itemToRemove, uniqueItemQuantities.get(itemToRemove)));
			
			// remove entry from quantity index
			uniqueItemQuantities.remove(itemToRemove);
			
			//remove catalogItem from item index
			uniqueCatalogItems.remove(itemToRemove);
		}

		
	}
	
	public void clearItems(){
		
	}
	
	// get all the line items
	// used to make order? or never used? maybe we need it
	public Set<LineItem> getAllItems(){
		return Collections.unmodifiableSet(items);
	}
	
	public double getBasePrice(){
		double basePrice = 0;
		for (LineItem item: items){
			basePrice += item.getBaseSalePrice();
		}
		return basePrice;
	}
	public double getSalePrice(ShippingInfo shipping){
		double salePrice = 0;
		for (LineItem item: items){
			salePrice += item.getSalePriceWithTax(shipping);
		}
		return salePrice;
	}
	
}
